# joint minimization of the training error term and the trp term
#theja 2010-July-20/21: porting probabilites.

#a. parameters related to training error term
param Ntrain > 0, integer; #number of training nodes
param dimLambda > 0, integer; # dimension of the parameter vector lambda, d for d-1 D data.
set vecNtrain := 1..Ntrain; #enumerating the training examples
set vecDimLambda := 1..dimLambda; #enumerating the dimensions of lambda
param xtrain{vecNtrain,vecDimLambda}; #creating an input feature matrix of size dimLambda*Ntrain. x = [x1 x2 1].
param ytrain{vecNtrain}; #creating label vector.

#b. parameters related to route cost term
param Ntest > 0, integer; # number of test nodes
set vecNtest := 1..Ntest; # enumerating the test nodes as Vertices
param d{vecNtest,vecNtest} >= 0; # creating an input ditance matrix of the size (test vertices) ^2.
param xtest{vecNtest,vecDimLambda};

#c. parameter weigning term1 wrt term2
param C1; #weight for term1
param C2; #weight for term2

#a. variables related to training error term
var lambda{vecDimLambda}; # the parameters of the probability estimator.

#b. variables related to route cost term 
var y{vecNtest,vecNtest} >=0 binary; # binary on-off variables indicating whether the edge exists in the solution.
var z{vecNtest,vecNtest} >=0; # flow variables indicating the flow on each edge.
var prob{vecNtest} >=0; #probabilities as flow values. dummy. see constraints "prob_2_lambda"
var cost2;#dummy variable


#objective:
minimize totalcost : C1*(sum{i in vecNtrain}log(1+exp(-ytrain[i]*(sum{j in vecDimLambda} lambda[j]*(xtrain[i,j]))))) + C2*(sum{i in vecNtest, j in vecNtest} d[i,j] * z[i,j]); 

#constraints:
#subject to lambda_1: lambda[1] = 0;
#subject to lambda_2: lambda[2] = .1;
#subject to lambda_3: lambda[3] = 1;
subject to dummy_cost2: cost2 = (sum{i in vecNtest, j in vecNtest} d[i,j] * z[i,j]);
subject to prob_2_lambda {i in vecNtest}: prob[i] = log(1+exp((sum{j in vecDimLambda} lambda[j]*xtest[i,j])));
subject to no_self_loop1 {i in vecNtest}: y[i,i] = 0; 			# No edge from node i to itself
subject to no_self_loop2 {i in vecNtest}: z[i,i] = 0; 			# No flow from node i to itself
subject to successor {i in vecNtest} : sum{j in vecNtest} y[i,j] = 1; 		# Exactly one edge out from each node
subject to predecessor {j in vecNtest} : sum{i in vecNtest} y[i,j] = 1;		# Exactly one edge into each node
	#Flow coming back to initial at end of the loop is p(1)
subject to flow_comming_back_to_node_1: sum{i in vecNtest} z[i,1] = prob[1]; 	
	#Change of flow after crossing node k is either p(k) or it is the sum of p’s minus p(1)
subject to flow_changes {k in vecNtest:k !=1}: sum{i in vecNtest} z[i,k] - sum{j in vecNtest} z[k,j] = prob[k];
subject to one_more_flow_change {k in vecNtest: k==1}: sum{i in vecNtest} z[i,k] - sum{j in vecNtest} z[k,j] = prob[1] - (sum{i1 in vecNtest} prob[i1]);
	#Connects flows z to indicators of edge y
subject to relation_btw_y_z {i in vecNtest,j in vecNtest: i!=1 && j!=1}: z[i,j] <= ((sum{i1 in vecNtest} prob[i1]) - prob[1])*y[i,j]; 
subject to relation_btw_y_z_1 {i in vecNtest}: z[i,1] <= prob[1]*y[i,1];
subject to relation_btw_y_z_2 {j in vecNtest}: z[1,j] <= (sum{i1 in vecNtest} prob[i1])*y[1,j];
